interface IRect {
    x: number; // 绘制起始点x
    y: number; // 绘制起始点y
    width: number; // 绘制宽度
    height: number; // 绘制高度
    theta: number; // 旋转角度
}

type RotateType = 'None' | 'CenterX' | 'CenterY'

interface IRealRect extends IRect {
    rotateType?: RotateType;
}

interface IPoint {
    x: number;
    y: number;
}

type OperationType = 'Scale' | 'EqualScale' | 'StretchX' | 'StretchY'

interface IOperation {
    type: OperationType; // 操作类型
    startPoint: IPoint; // 起始点
    endPoint: IPoint; // 结束点
}

const matrixMultiply: (a: number[][], b: number[][]) => number[][] = (a, b) => {
    let result: number[][] = []
    for (let i = 0; i < a.length; i++) {
        result[i] = [];
        for (let j = 0; j < b[0].length; j++) {
            let sum = 0;
            for (let k = 0; k < b.length; k++) {
                sum += a[i][k] * b[k][j];
            }
            result[i][j] = sum;
        }
    }
    return result;
}

const translation: (x: number, y: number) => { tm: number[][], tm_inv: number[][] } = (x, y) => {
    return {
        tm: [
            [1, 0, -x],
            [0, 1, -y],
            [0, 0, 1]
        ],
        tm_inv: [
            [1, 0, x],
            [0, 1, y],
            [0, 0, 1]
        ],
    }
}

const rotation: (theta: number) => { r_theta: number[][], r_theta_inv: number[][] } = (theta) => {
    const theta_in_radians = theta * Math.PI / 180
    const sin = Math.sin(theta_in_radians)
    const cos = Math.cos(theta_in_radians)
    return {
        r_theta: [
            [cos, sin, 0],
            [-sin, cos, 0],
            [0, 0, 1]
        ],
        r_theta_inv: [
            [cos, -sin, 0],
            [sin, cos, 0],
            [0, 0, 1]
        ],
    }
}

const diag: (data: number[]) => number[][] = (data) => {
    let matrix : number[][] = [];
    for (let i = 0; i < data.length; i++) {
        matrix[i] = [];
        for (let j = 0; j < data.length; j++) {
            if (i === j) {
                matrix[i][j] = data[i]; // 或者任何你想在对角线上放置的值
            } else {
                matrix[i][j] = 0;
            }
        }
    }
    return matrix;
}

const coordination_conversion: (matrix: number[][], o : IPoint) => IPoint = (matrix, o) => {
    const o_arrow = [
        [o.x],
        [o.y],
        [1]
    ]
    const t_arrow = matrixMultiply(matrix, o_arrow)
    return {
        x: t_arrow[0][0],
        y: t_arrow[1][0]
    }
}

const buildSimpleDeformRect: {
    [key in OperationType]: (s: IPoint, e: IPoint) => number[][]
} = {
    ['Scale']: (s: IPoint,e : IPoint) => {
        if (s.x == 0 || s.y == 0) { // 操作起点不能在变换后坐标系的原点或者坐标轴上
            return diag([1, 1]);
        }
        // 操作结束点不能在变换后坐标系的原点或者坐标轴上，如果坐标值的绝对值小于1，则将坐标值除以绝对值，即将坐标值绝对值的最小值为1
        if (Math.abs(e.x) < 1) {
            e.x = e.x / Math.abs(e.x);
        }
        if (Math.abs(e.y) < 1) {
            e.y = e.y / Math.abs(e.y);
        }
        return diag([e.x / s.x, e.y / s.y]);
    },
    ['EqualScale']: (s: IPoint,e : IPoint) => {
        if (s.x == 0 || s.y == 0) { // 操作起点不能在变换后坐标系的原点或者坐标轴上
            return diag([1, 1]);
        }
        // 操作结束点不能在变换后坐标系的原点或者坐标轴上，如果坐标值的绝对值小于1，则将坐标值除以绝对值，即将坐标值绝对值的最小值为1
        if (Math.abs(e.x) < 1) {
            e.x = e.x/ Math.abs(e.x)
        }
        if (Math.abs(e.y) < 1) {
            e.y = e.y / Math.abs(e.y)
        }
        // 计算两个方向上的比例
        const ratioOfex = e.x / s.x
        const ratioOfey = e.y / s.y
        // 找到更靠近1的比例
        if (Math.abs(Math.abs(ratioOfex) - 1) < Math.abs(Math.abs(ratioOfey) - 1)) {
            return diag([ratioOfex, ratioOfex]);
        } else {
            return diag([ratioOfey, ratioOfey]);
        }
    },
    ['StretchX']: (s: IPoint,e : IPoint) => {
        if (s.x == 0) { // 操作起点不能在变换后坐标系的Y轴上
            return diag([1, 1]);
        }
        // 操作结束点不能在变换后坐标系的Y轴上，如果坐标值的绝对值小于1，则将坐标值除以绝对值，即将坐标值绝对值的最小值为1
        if (Math.abs(e.x) < 1) {
            e.x = e.x / Math.abs(e.x);
        }
        return diag([e.x / s.x, 1]);
    },
    ['StretchY']: (s: IPoint,e : IPoint) => {
        if (s.y == 0) { // 操作起点不能在变换后坐标系的X轴上
            return diag([1, 1]);
        }
        // 操作结束点不能在变换后坐标系的原点或者坐标轴上，如果坐标值的绝对值小于1，则将坐标值除以绝对值，即将坐标值绝对值的最小值为1
        if (Math.abs(e.y) < 1) {
            e.y = e.y / Math.abs(e.y);
        }
        return diag([1, e.y / s.y]);
    }
}

const covertToRect: (rect: IRealRect) => IRect = (rect) => {
    switch (rect.rotateType) {
        case "None":
            return rect
        case "CenterX": // scaleY(-1)
            return {
                x: rect.x,
                y: rect.y + rect.height,
                width: rect.width,
                height: -rect.height,
                theta: rect.theta
            }
        case "CenterY": // scaleX(-1)
            return {
                x: rect.x + rect.width,
                y: rect.y,
                width: -rect.width,
                height: rect.height,
                theta: rect.theta
            }
        default:
            return rect
    }
}

const covertToRealRect: (rect: IRect) => IRealRect = (rect) => {
    if (rect.width > 0 && rect.height > 0) {
        return {
            rotateType: "None",
            ...rect
        }
    }
    if (rect.width < 0 && rect.height > 0) {
        return {
            x: rect.x + rect.width,
            y: rect.y,
            width: -rect.width,
            height: rect.height,
            theta: rect.theta,
            rotateType: "CenterY"
        }
    }
    if (rect.width > 0 && rect.height < 0) {
        return {
            x: rect.x,
            y: rect.y + rect.height,
            width: rect.width,
            height: -rect.height,
            theta: rect.theta,
            rotateType: "CenterX"
        }
    }
    if (rect.width < 0 && rect.height < 0) {
        return {
            x: rect.x + rect.width,
            y: rect.y + rect.height,
            width: -rect.width,
            height: -rect.height,
            theta: (rect.theta + 180) % 360,
            rotateType: "None"
        }
    }
    return {
        rotateType: "None",
        ...rect
    }
}

export const rectDeform = (originalRealRect: IRealRect, fixedPoint: IPoint, startPoint: IPoint) => {
    const originalRect = covertToRect(originalRealRect)
    const { tm: p1, tm_inv: p1_inv } = translation(
        originalRect.x + originalRect.width / 2,
        originalRect.y + originalRect.height / 2
    ) // 将坐标原点平移到矩形中心
    const { r_theta, r_theta_inv } = rotation(originalRect.theta) // 坐标系旋转矩阵
    const { tm: p2, tm_inv: p2_inv } = translation(
        fixedPoint.x - originalRect.width / 2,
        fixedPoint.y - originalRect.height / 2
    ) // 将坐标原点平移到固定点
    const coordination_conversion_matrix = matrixMultiply(matrixMultiply(p2, r_theta), p1)
    const coordination_conversion_matrix_inv = matrixMultiply(matrixMultiply(p1_inv, r_theta_inv), p2_inv)
    const s = coordination_conversion(coordination_conversion_matrix, startPoint); // 起始点转换后坐标
    return (endPoint: IPoint, type: OperationType) => {
        const e = coordination_conversion(coordination_conversion_matrix, endPoint); // 结束点转换后坐标
        const A = buildSimpleDeformRect[type](s, e); // 变换矩阵
        const Rect = [
            [-fixedPoint.x, originalRect.width - fixedPoint.x],
            [-fixedPoint.y, originalRect.height - fixedPoint.y]
        ]
        const RectAfterOperation = matrixMultiply(A, Rect);
        const width = RectAfterOperation[0][1] - RectAfterOperation[0][0]
        const height = RectAfterOperation[1][1] - RectAfterOperation[1][0]
        const helfOfWidth = width / 2;
        const helfOfHeight = height / 2;
        const rectCenterPoint = coordination_conversion(coordination_conversion_matrix_inv, {
            x: RectAfterOperation[0][0] + helfOfWidth,
            y: RectAfterOperation[1][0] + helfOfHeight
        });
        const x = rectCenterPoint.x - helfOfWidth
        const y = rectCenterPoint.y - helfOfHeight
        return covertToRealRect({
            x,
            y,
            width,
            height,
            theta: originalRect.theta
        })
    }
}


const rect: IRect = {
    x: 40,
    y: 40,
    width: 40,
    height: 20,
    theta: 90
}

const operation: IOperation = {
    type: 'Scale',
    startPoint: {
        x: 50,
        y: 70
    },
    endPoint: {
        x: 80,
        y: 80
    }
}

console.log("--------缩放--------")
const f1 = rectDeform(rect, {x: 0, y: 0}, operation.startPoint)
for (let i = 0; i < 40; i++) {
    let start = performance.now()
    let rect = f1(operation.endPoint, "Scale")
    let end = performance.now()
    console.log(rect, end - start)
}
console.log("------等比缩放------")
for (let i = 0; i < 40; i++) {
    let start = performance.now()
    let rect = f1(operation.endPoint, "EqualScale")
    let end = performance.now()
    console.log(rect, end - start)
}
console.log("------X轴拉伸------")
const f2 = rectDeform(rect, {x: 0, y: 0}, operation.startPoint)
for (let i = 0; i < 40; i++) {
    let start = performance.now()
    let rect = f2(operation.endPoint, "StretchX")
    let end = performance.now()
    console.log(rect, end - start)
}
console.log("------Y轴拉伸------")
for (let i = 0; i < 40; i++) {
    let start = performance.now()
    let rect = f2(operation.endPoint, "StretchY")
    let end = performance.now()
    console.log(rect, end - start)
}

const f = rectDeform({x: 10, y:10, width: 10, height: 10, theta: 0}, {x: 10, y: 10}, {x: 10, y: 10})

console.log(f({x: 0, y: 0}, "Scale"))
console.log(f({x: 0, y: 0}, "EqualScale"))

export {
    IRect,
    IRealRect,
    IPoint,
    OperationType,
    IOperation
}